package com.tozed.android.launcher;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import android.app.AlertDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.res.Resources;
import android.graphics.Point;
import android.graphics.Rect;
import android.util.AttributeSet;
import android.util.Log;
import android.util.SparseArray;
import android.util.TypedValue;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnLongClickListener;
import android.view.View.OnTouchListener;
import android.view.animation.AccelerateDecelerateInterpolator;
import android.view.animation.Animation;
import android.view.animation.AnimationSet;
import android.view.animation.RotateAnimation;
import android.view.animation.ScaleAnimation;
import android.view.animation.TranslateAnimation;
import android.view.ViewGroup;
import android.widget.Toast;

import com.tozed.android.launcher.R;

/**
 * Home pge Edit
 *
 */
public class HomeEditView extends ViewGroup implements OnTouchListener, HomeEditViewItem.defalutPagechangeListener,
        OnLongClickListener {
    private static final String TAG = "HomeEditView";
    private Context mContext;
    private List<View> mChilds;

    private static final int ANIMATION_DURATION = 250;


    private int SMALL_WIDTH;
    private int SMALL_HEIGHT;

    private int BIG_WIDTH;
    private int BIG_HEIGHT;
    // the x gap of pages
    private static final int PAGE_GAP_WIDTH = 10;
    // the y gap of pages
    private static final int PAGE_GAP_HEIGHT = 20;
    // the hieght of delete zone
    private static final int DELETE_ZONE_HEIGHT = 80;

    int dragged = -1;
    // judge whether moving
    private boolean movingView = false;

    private int dragLeft;
    private int dragTop;
    private HomeEditViewItem add;
    private AlertDialog mDialog = null;

    public class PageInfo implements Comparable<PageInfo> {
        // origin page
        public int originPage = -1;
        // the page after edit
        public int currentPage = -1;
        public boolean isDefault = false;

        @Override
        public int compareTo(PageInfo another) {
            return currentPage - another.currentPage;
        }
    }

    public interface OnClickPageListener {
        public void onClickPage(int index, List<PageInfo> pages);
    }

    private OnClickPageListener clickPage;
    public void setOnClickPageListener(OnClickPageListener listener) {
        this.clickPage = listener;
    }

    @Override
    public void onDefaultPageChanged(HomeEditViewItem view) {
        view.setDefault(true);
        for (int i = 0; i < getChildCount(); i++) {
            View child = getChildAt(i);
            if (child == add) {
                continue;
            }
            HomeEditViewItem itemView = (HomeEditViewItem) child;
            if (itemView != view && itemView.isDefault()) {
                itemView.setDefault(false);
            }
        }
        if (mToast != null) mToast.cancel();
        mToast = Toast.makeText(mContext, R.string.default_workspace_changed, Toast.LENGTH_SHORT);
        mToast.show();
    }

    private OnClickListener onClickListener = new OnClickListener() {

        @Override
        public void onClick(View v) {
            Log.d(TAG, "onClick");
            if (v == add) {
                View view = createView(getChildCount() - 1);
                addView(view, getChildCount() - 1);
                if (getChildCount() == 9) {
                    Log.d(TAG, "Already max, delete add view");
                    removeView(add);
                }

                requestLayout();
            } else {
                if (clickPage != null) {
                    List<PageInfo> pages = new ArrayList<PageInfo>();
                    int page = 0;
                    for (int i = 0; i < getChildCount(); i++) {
                        View child = getChildAt(i);
                        if (child == add) {
                            continue;
                        }

                        PageInfo info = new PageInfo();
                        info.originPage = (Integer) child.getTag();
                        info.currentPage = i;
                        if (((HomeEditViewItem) child).isDefault())
                            info.isDefault = true;
                        pages.add(info);
                        if(v == child) {
                            page  = i;
                        }
                    }

                    clickPage.onClickPage(page, pages);
                }
            }
        }
    };

    public List<PageInfo> getPagesInfo() {
        List<PageInfo> pages = new ArrayList<PageInfo>();
        for (int i = 0; i < getChildCount(); i++) {
            View child = getChildAt(i);
            if (child == add) {
                continue;
            }

            PageInfo info = new PageInfo();
            info.originPage = (Integer) child.getTag();
            info.currentPage = i;
            if (((HomeEditViewItem) child).isDefault())
                info.isDefault = true;
            pages.add(info);
        }
        return pages;
    }

    private SparseArray<Integer> newPositions = new SparseArray<Integer>();

    private int initX;
    private int initY;
    private int lastTouchX;
    private int lastTouchY;

    private int lastTarget = -1;
    private Point startPoint;

    private DeleteDropZoneView deleteZone;
    private Toast mToast;

    public HomeEditView(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public HomeEditView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        this.mContext = context.getApplicationContext();
        setOnTouchListener(this);
        setOnLongClickListener(this);
        SMALL_WIDTH = dip2px(mContext, mContext.getResources().getConfiguration().screenWidthDp / 4);
        SMALL_HEIGHT = dip2px(mContext, mContext.getResources().getConfiguration().screenHeightDp / 4);

        BIG_WIDTH = dip2px(mContext, mContext.getResources().getConfiguration().screenWidthDp / 4);
        BIG_HEIGHT = dip2px(mContext, mContext.getResources().getConfiguration().screenHeightDp / 4);

        Log.i(TAG, "SMALL_WIDTH is " + SMALL_WIDTH + " SMALL_HEIGHT is " + SMALL_HEIGHT +
                " BIG_WIDTH is " + BIG_WIDTH + " BIG_HEIGHT is " + BIG_HEIGHT );

    }

    @Override
    protected void onAttachedToWindow() {
        super.onAttachedToWindow();
        ViewGroup parent = (ViewGroup) this.getParent();
        if (deleteZone == null) {
            deleteZone = (DeleteDropZoneView)parent.findViewById(R.id.deletedropzone);
        }
    }

    public static int dip2px(Context context, float dpValue) {
        final float scale = context.getResources().getDisplayMetrics().density;
         return (int) (dpValue * scale + 0.5f);
     }

    public void addViews(List<View> views) {
        removeAllViews();

        for (int i = 0; i < views.size(); i++) {
            View view = views.get(i);
            if(view instanceof HomeEditViewItem) {
                ((HomeEditViewItem) view).setDefaultChangeListener(this);
            }
            addView(view);
            view.setTag(i);
            newPositions.put(i, i);
        }

        if (views.size() < 8) {
            addView(createAddView());
        }
    }

    private void printTag() {
        for (int i = 0; i < getChildCount(); i++) {
            View child = getChildAt(i);
        }
    }

    @Override
    public boolean onTouch(View v, MotionEvent event) {
        int action = event.getAction();

        switch (action & MotionEvent.ACTION_MASK) {
        case MotionEvent.ACTION_DOWN:
            initX = (int) event.getX();
            initY = (int) event.getY();

            lastTouchX = (int) event.getX();
            lastTouchY = (int) event.getY();
            break;
        case MotionEvent.ACTION_MOVE:
            eventMove(event);
            break;
        case MotionEvent.ACTION_UP:
            touchUp(event);
            break;

        default:
            break;
        }

        if (aViewIsDragged()) {
            return true;
        }

        return false;
    }

    private void touchUp(MotionEvent event) {
        if (!aViewIsDragged()) {
            if (onClickListener != null) {
                View clickedView = getChildAt(getTargetAtCoor((int) event.getX(), (int) event.getY()));
                Log.d(TAG, "clickedView : " + clickedView);
                if(clickedView != null)
                    onClickListener.onClick(clickedView);
            }
        } else {
            getChildAt(dragged).setScaleX(1.0f);
            getChildAt(dragged).setScaleY(1.0f);
            boolean draggedDeleted = touchUpInDeleteZoneDrop(lastTouchX, lastTouchY);
            if (draggedDeleted) {
                handlePagedelete();
            } else {
                manageChildrenReordering(false);
            }
        }
    }

    private void handlePagedelete() {
        if (getChildCount() < 3) {
            if (mToast != null)
                mToast.cancel();
            mToast = Toast.makeText(mContext, R.string.one_page_least, Toast.LENGTH_SHORT);
            mToast.show();
            manageChildrenReordering(false);
            return;
        }
        final HomeEditViewItem view = (HomeEditViewItem) getChildAt(dragged);
        boolean isEmpty = view.isCellEmpty();
        Log.d(TAG, "isEmpty : " + isEmpty);
        if (!isEmpty) {
            if (mDialog == null) {
                mDialog = new AlertDialog.Builder(getContext())
                        .setMessage(R.string.delete_page_message)
                        .setIcon(android.R.drawable.ic_dialog_alert)
                        .setTitle(R.string.delete_page_title)
                        .setPositiveButton(android.R.string.yes, new DialogInterface.OnClickListener() {
                                @Override
                                public void onClick(DialogInterface dialog, int which) {
                                    if (view.isDefault()) {
                                        ((HomeEditViewItem) getChildAt(dragged > 0? dragged -1 : dragged + 1))
                                                .setDefault(true);
                                    }
                                    manageChildrenReordering(true);
                                    dialog.dismiss();
                                }
                        })
                        .setNegativeButton(android.R.string.no, new DialogInterface.OnClickListener() {
                            @Override
                            public void onClick(DialogInterface dialog, int which) {
                                manageChildrenReordering(false);
                                dialog.dismiss();
                            }
                        })
                        .create();
                mDialog.setCanceledOnTouchOutside(false);
            }
            mDialog.show();
        } else {
            if (view.isDefault()) {
                ((HomeEditViewItem) getChildAt(dragged > 0? dragged -1 : dragged + 1)).setDefault(true);
            }
            manageChildrenReordering(true);
        }
    }
    private void cancelAnimations() {
        for (int i = 0; i < getChildCount(); i++) {
            if (i != dragged) {
                View child = getChildAt(i);
                child.clearAnimation();
            }
        }
    }

    private void manageChildrenReordering(boolean draggedDeleted) {
        if (draggedDeleted) {
            animateDeleteDragged();
            reorderChildrenWhenDraggedIsDeleted();
        } else {
            reorderChildren();
        }
        movingView = false;
        dragged = -1;
        lastTarget = -1;
        cancelAnimations();
    }

    private void reorderChildrenWhenDraggedIsDeleted() {
        Integer newDraggedPosition = newPositions.get(dragged,dragged);

        List<View> children = cleanUnorderedChildren();
        addReorderedChildrenToParent(children);

        removeViewAt(newDraggedPosition);
        if (add != null && add.getParent() != this) {
            addView(createAddView(), getChildCount());
        }

        requestLayout();
    }

    private void animateDeleteDragged() {
        ScaleAnimation scale = new ScaleAnimation(1.4f, 0f, 1.4f, 0f);
        scale.setDuration(200);
        scale.setFillAfter(true);
        scale.setFillEnabled(true);

        getChildAt(dragged).clearAnimation();
        getChildAt(dragged).startAnimation(scale);
    }

    private void reorderChildren() {
        List<View> children = cleanUnorderedChildren();
        addReorderedChildrenToParent(children);
        requestLayout();
    }

    private void removeItemChildren(List<View> children) {
        for (View child : children) {
            removeView(child);
        }
    }

    private List<View> cleanUnorderedChildren() {
        List<View> children = saveChildren();
        removeItemChildren(children);
        return children;
    }

    private void addReorderedChildrenToParent(List<View> children) {
        List<View> reorderedViews = reeorderView(children);
        newPositions.clear();

        for (View view : reorderedViews) {
            if (view != null)
                addView(view);
        }
    }

    private List<View> reeorderView(List<View> children) {
        View[] views = new View[children.size()];

        for (int i = 0; i < children.size(); i++) {
            int position = newPositions.get(i, -1);
            if (position != -1) {
                views[position] = children.get(i);
            } else {
                views[i] = children.get(i);
            }
        }

        return new ArrayList<View>(Arrays.asList(views));
    }

    private List<View> saveChildren() {
        List<View> children = new ArrayList<View>();
        for (int i = 0; i < getChildCount(); i++) {
            View child = getChildAt(i);
            child.clearAnimation();
            children.add(child);
        }
        return children;
    }

    private void eventMove(MotionEvent event) {
        if (movingView && aViewIsDragged()) {
            lastTouchX = (int) event.getX();
            lastTouchY = (int) event.getY();

            moveDraggedView(lastTouchX, lastTouchY);
            manageSwapPosition(lastTouchX, lastTouchY);
            manageDeleteZoneHover(lastTouchX, lastTouchY);
        }
    }

    private void manageSwapPosition(int x, int y) {
        int target = getTargetAtCoor(x, y);
        if (target != -1 && target != lastTarget) {
            animateGap(target);
            lastTarget = target;
        }
    }

    private int currentViewAtPosition(int targetLocation) {
        int viewAtPosition = targetLocation;
        for (int i = 0; i < newPositions.size(); i++) {
            int value = newPositions.valueAt(i);
            if (value == targetLocation) {
                viewAtPosition = newPositions.keyAt(i);
                break;
            }
        }

        return viewAtPosition;
    }

    private void animateGap(int target) {
        int viewAtPosition = currentViewAtPosition(target);
        if (getChildAt(viewAtPosition) == add) {
            return;
        }

        View origin = getChildAt(viewAtPosition);
        int originLeft = origin.getLeft();
        int originTop = origin.getTop();
        if (viewAtPosition == dragged) {
            originLeft = dragLeft;
            originTop = dragTop;
        }

        View curr = getChildAt(target);
        int currLeft = curr.getLeft();
        int currTop = curr.getTop();
        if (target == dragged) {
            currLeft = dragLeft;
            currTop = dragTop;
        }

        View tar = getChildAt(newPositions.get(dragged, dragged));
        int tarLeft = tar.getLeft();
        int tarTop = tar.getTop();
        if (newPositions.get(dragged, dragged) == dragged) {
            tarLeft = dragLeft;
            tarTop = dragTop;
        }

        Point oldOffset = new Point();
        oldOffset.x = currLeft - originLeft;
        oldOffset.y = currTop - originTop;

        Point newOffset = new Point();
        newOffset.x = tarLeft - originLeft;
        newOffset.y = tarTop - originTop;

        animateMoveToNewPosition(getChildAt(viewAtPosition), oldOffset,
                newOffset);

        saveNewPosition(target, viewAtPosition);
    }

    private void saveNewPosition(int target, int viewInTarget) {
        newPositions.put(viewInTarget, newPositions.get(dragged, dragged));
        newPositions.put(dragged, target);


    }

    // get the view on the point
    private int getTargetAtCoor(int x, int y) {
        int ret = -1;
        for (int i = 0; i < getChildCount(); i++) {
            View child = getChildAt(i);
            if (child == getChildAt(dragged)) {
                int count = getChildCount();
                if (count < 5) {
                    if ((x > dragLeft && x < dragLeft + SMALL_WIDTH)
                            && (y > dragTop && y < dragTop + SMALL_HEIGHT)) {
                        return i;
                    }
                } else {
                    if ((x > dragLeft && x < dragLeft + BIG_WIDTH)
                            && (y > dragTop && y < dragTop + BIG_HEIGHT)) {
                        return i;
                    }
                }

                continue;
            }

            if (isPointInsideView(x, y, child)) {
                return i;
            }
        }

        return ret;
    }

    private void moveDraggedView(int x, int y) {
        View childAt = getChildAt(dragged);
        int width = childAt.getMeasuredWidth();
        int height = childAt.getMeasuredHeight();

        int l = x - (1 * width / 2);
        int t = y - (1 * height / 2);

        childAt.layout(l, t, l + width, t + height);
    }

    private void updateSize() {
        int count = getChildCount() - 1;
        if (count < 5) {
            for (int i = 0; i < count; i++) {
                View view = getChildAt(i);
                float wid = view.getWidth();
                float hei = view.getHeight();
                view.setScaleX(SMALL_WIDTH / wid);
                view.setScaleY(SMALL_HEIGHT / hei);
            }
        } else {
            for (int i = 0; i < count; i++) {
                View view = getChildAt(i);
                float wid = view.getWidth();
                float hei = view.getHeight();
                view.setScaleX(BIG_WIDTH / wid);
                view.setScaleY(BIG_HEIGHT / hei);
            }
        }
    }

    @Override
    protected void onLayout(boolean changed, int l, int t, int r, int b) {
        int count = getChildCount();
        Log.d(TAG, "count == " + count);

        if (count < 3) {
            int left = getWidth() / 2 - (SMALL_WIDTH * 2 + PAGE_GAP_WIDTH) / 2;
            for (int i = 0; i < count; i++) {
                View child = getChildAt(i);
                if (child.getVisibility() == View.GONE) {
                    continue;
                }
                int top = (getHeight() - DELETE_ZONE_HEIGHT) / 2 - (SMALL_HEIGHT / 2) + DELETE_ZONE_HEIGHT;

                child.layout(left, top, left + SMALL_WIDTH,
                        SMALL_HEIGHT + top);
                left += SMALL_WIDTH + PAGE_GAP_WIDTH;
            }
        } else if (count == 3) {
            int left = getWidth() / 2 - (SMALL_WIDTH * 2 + PAGE_GAP_WIDTH) / 2;
            int top = (getHeight() - DELETE_ZONE_HEIGHT) / 2 - (SMALL_HEIGHT * 2 + PAGE_GAP_HEIGHT) / 2 + DELETE_ZONE_HEIGHT;
            for (int i = 0; i < count; i++) {
                View child = getChildAt(i);
                if (child.getVisibility() == View.GONE) {
                    continue;
                }

                if (i == 2) {
                    child.layout(getWidth() / 2 - SMALL_WIDTH / 2, SMALL_HEIGHT
                            + PAGE_GAP_HEIGHT + top, getWidth()
                            / 2 - SMALL_WIDTH / 2 + SMALL_WIDTH, SMALL_HEIGHT
                            * 2 + PAGE_GAP_HEIGHT + top);
                } else {
                    child.layout(left, top, left + SMALL_WIDTH,
                            SMALL_HEIGHT + top);
                    left += SMALL_WIDTH + PAGE_GAP_WIDTH;
                }

            }
        } else if (count == 4) {
            int left = getWidth() / 2 - (SMALL_WIDTH * 2 + PAGE_GAP_WIDTH) / 2;
            int left2 = getWidth() / 2 - (SMALL_WIDTH * 2 + PAGE_GAP_WIDTH) / 2;
            int top = (getHeight() - DELETE_ZONE_HEIGHT) / 2 - (SMALL_HEIGHT * 2 + PAGE_GAP_HEIGHT) / 2 + DELETE_ZONE_HEIGHT;
            for (int i = 0; i < count; i++) {
                View child = getChildAt(i);
                if (child.getVisibility() == View.GONE) {
                    continue;
                }

                if (i >= 2) {
                    child.layout(left2, SMALL_HEIGHT + PAGE_GAP_HEIGHT
                            + top, left2 + SMALL_WIDTH,
                            SMALL_HEIGHT * 2 + PAGE_GAP_HEIGHT
                                    + top);
                    left2 += SMALL_WIDTH + PAGE_GAP_WIDTH;
                } else {
                    child.layout(left, top, left + SMALL_WIDTH,
                            SMALL_HEIGHT + top);
                    left += SMALL_WIDTH + PAGE_GAP_WIDTH;
                }

            }
        } else if (count == 5) {
            int left1 = getWidth() / 2 - (BIG_WIDTH * 2 + PAGE_GAP_WIDTH) / 2;
            int left2 = getWidth() / 2 - (BIG_WIDTH / 2);
            int left3 = getWidth() / 2 - (BIG_WIDTH * 2 + PAGE_GAP_WIDTH) / 2;
            int top = (getHeight() - DELETE_ZONE_HEIGHT) / 2 - (SMALL_HEIGHT * 3 + PAGE_GAP_HEIGHT * 2) / 2 + DELETE_ZONE_HEIGHT;

            for (int i = 0; i < count; i++) {
                View child = getChildAt(i);
                if (child.getVisibility() == View.GONE) {
                    continue;
                }

                if (i < 2) {
                    child.layout(left1, top, left1 + BIG_WIDTH,
                            BIG_HEIGHT + top);
                    left1 += BIG_WIDTH + PAGE_GAP_WIDTH;
                } else if (i == 2) {
                    child.layout(left2, BIG_HEIGHT + PAGE_GAP_HEIGHT
                            + top, left2 + BIG_WIDTH, BIG_HEIGHT
                            * 2 + PAGE_GAP_HEIGHT + top);
                } else {
                    child.layout(left3, BIG_HEIGHT * 2 + PAGE_GAP_HEIGHT * 2
                            + top, left3 + BIG_WIDTH, BIG_HEIGHT
                            * 2 + PAGE_GAP_HEIGHT * 2 + BIG_HEIGHT
                            + top);
                    left3 += BIG_WIDTH + PAGE_GAP_WIDTH;
                }

            }
        } else if (count == 6) {
            int left1 = getWidth() / 2 - (BIG_WIDTH * 2 + PAGE_GAP_WIDTH) / 2;
            int left2 = left1;
            int left3 = getWidth() / 2 - (BIG_WIDTH * 2 + PAGE_GAP_WIDTH) / 2;
            int top = (getHeight() - DELETE_ZONE_HEIGHT) / 2 - (SMALL_HEIGHT * 3 + PAGE_GAP_HEIGHT * 2) / 2 + DELETE_ZONE_HEIGHT;

            for (int i = 0; i < count; i++) {
                View child = getChildAt(i);
                if (child.getVisibility() == View.GONE) {
                    continue;
                }

                if (i < 2) {
                    child.layout(left1, top, left1 + BIG_WIDTH,
                            BIG_HEIGHT + top);
                    left1 += BIG_WIDTH + PAGE_GAP_WIDTH;
                } else if (i >= 2 && i < 4) {
                    child.layout(left2, BIG_HEIGHT + PAGE_GAP_HEIGHT
                            + top, left2 + BIG_WIDTH, BIG_HEIGHT
                            * 2 + PAGE_GAP_HEIGHT + top);
                    left2 += BIG_WIDTH + PAGE_GAP_WIDTH;
                } else {
                    child.layout(left3, BIG_HEIGHT * 2 + PAGE_GAP_HEIGHT * 2
                            + top, left3 + BIG_WIDTH, BIG_HEIGHT
                            * 2 + PAGE_GAP_HEIGHT * 2 + BIG_HEIGHT
                            + top);
                    left3 += BIG_WIDTH + PAGE_GAP_WIDTH;
                }

            }
        } else if (count == 7) {
            int left1 = getWidth() / 2 - (BIG_WIDTH * 2 + PAGE_GAP_WIDTH) / 2;
            int left2 = getWidth() / 2 - (BIG_WIDTH * 3 + 2 * PAGE_GAP_WIDTH)
                    / 2;
            int left3 = getWidth() / 2 - (BIG_WIDTH * 2 + PAGE_GAP_WIDTH) / 2;
            int top = (getHeight() - DELETE_ZONE_HEIGHT) / 2 - (SMALL_HEIGHT * 3 + PAGE_GAP_HEIGHT * 2) / 2 + DELETE_ZONE_HEIGHT;
            for (int i = 0; i < count; i++) {
                View child = getChildAt(i);
                if (child.getVisibility() == View.GONE) {
                    continue;
                }

                if (i < 2) {
                    child.layout(left1, top, left1 + BIG_WIDTH,
                            BIG_HEIGHT + top);
                    left1 += BIG_WIDTH + PAGE_GAP_WIDTH;
                } else if (i >= 2 && i < 5) {
                    child.layout(left2, BIG_HEIGHT + PAGE_GAP_HEIGHT
                            + top, left2 + BIG_WIDTH, BIG_HEIGHT
                            * 2 + PAGE_GAP_HEIGHT + top);
                    left2 += BIG_WIDTH + PAGE_GAP_WIDTH;
                } else {
                    child.layout(left3, BIG_HEIGHT * 2 + PAGE_GAP_HEIGHT * 2
                            + top, left3 + BIG_WIDTH, BIG_HEIGHT
                            * 2 + PAGE_GAP_HEIGHT * 2 + BIG_HEIGHT
                            + top);
                    left3 += BIG_WIDTH + PAGE_GAP_WIDTH;
                }

            }
        } else if (count == 8) {
            int left1 = getWidth() / 2 - (BIG_WIDTH * 3 + 2 * PAGE_GAP_WIDTH)
                    / 2;
            int left2 = getWidth() / 2 - (BIG_WIDTH * 2 + PAGE_GAP_WIDTH) / 2;
            int left3 = left1;
            int top = (getHeight() - DELETE_ZONE_HEIGHT) / 2 - (SMALL_HEIGHT * 3 + PAGE_GAP_HEIGHT * 2) / 2 + DELETE_ZONE_HEIGHT;

            for (int i = 0; i < count; i++) {
                View child = getChildAt(i);
                if (child.getVisibility() == View.GONE) {
                    continue;
                }

                if (i < 3) {
                    child.layout(left1, top, left1 + BIG_WIDTH,
                            BIG_HEIGHT + top);
                    left1 += BIG_WIDTH + PAGE_GAP_WIDTH;
                } else if (i >= 3 && i < 5) {
                    child.layout(left2, BIG_HEIGHT + PAGE_GAP_HEIGHT
                            + top, left2 + BIG_WIDTH, BIG_HEIGHT
                            * 2 + PAGE_GAP_HEIGHT + top);
                    left2 += BIG_WIDTH + PAGE_GAP_WIDTH;
                } else {
                    child.layout(left3, BIG_HEIGHT * 2 + PAGE_GAP_HEIGHT * 2
                            + top, left3 + BIG_WIDTH, BIG_HEIGHT
                            * 2 + PAGE_GAP_HEIGHT * 2 + BIG_HEIGHT
                            + top);
                    left3 += BIG_WIDTH + PAGE_GAP_WIDTH;
                }

            }
        }
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        Log.d(TAG, "onMeasure");
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        int count = getChildCount();

        if (count < 5) {
            for (int i = 0; i < count; i++) {
                View child = getChildAt(i);
                child.measure(MeasureSpec.makeMeasureSpec(SMALL_WIDTH,
                        MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(
                        SMALL_HEIGHT, MeasureSpec.EXACTLY));
            }
        } else {
            for (int i = 0; i < count; i++) {
                View child = getChildAt(i);
                child.measure(MeasureSpec.makeMeasureSpec(BIG_WIDTH,
                        MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(
                        BIG_HEIGHT, MeasureSpec.EXACTLY));
            }
        }
    }

    private float getPixelFromDip(int size) {
        Resources r = getResources();
        float px = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, size,
                r.getDisplayMetrics());
        return px;
    }

    @Override
    public boolean onLongClick(View v) {
        if ((dragged = positionForView()) != -1) {
            if (getChildAt(dragged) == add) {
                // can't move add view
                return true;
            }

            startPoint = new Point();
            dragLeft = (int) getChildAt(dragged).getLeft();
            dragTop = (int) getChildAt(dragged).getTop();

            movingView = true;
//            animateMoveAllItems();
            animateDragged();

            return true;
        }

        return false;
    }

    private int positionForView() {
        for (int i = 0; i < getChildCount(); i++) {
            View child = getChildAt(i);
            if (isPointInsideView(initX, initY, child)) {
                return i;
            }
        }

        return -1;
    }

    private boolean isPointInsideView(float x, float y, View view) {
        int viewX = view.getLeft();
        int viewY = view.getTop();

        if (pointIsInsideViewBounds(x, y, view, viewX, viewY)) {
            return true;
        } else {
            return false;
        }
    }

    private boolean pointIsInsideViewBounds(float x, float y, View view,
            int viewX, int viewY) {
        return (x > viewX && x < (viewX + view.getWidth()))
                && (y > viewY && y < (viewY + view.getHeight()));
    }

    private void animateMoveAllItems() {
        Animation rotateAnimation = createFastRotateAnimation();

        for (int i = 0; i < getChildCount(); i++) {
            View child = getChildAt(i);
            child.startAnimation(rotateAnimation);
        }
    }

    private Animation createFastRotateAnimation() {
        Animation rotate = new RotateAnimation(-2.0f, 2.0f,
                Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF,
                0.5f);

        rotate.setRepeatMode(Animation.REVERSE);
        rotate.setRepeatCount(Animation.INFINITE);
        rotate.setDuration(60);
        rotate.setInterpolator(new AccelerateDecelerateInterpolator());

        return rotate;
    }

    private void animateDragged() {
        if (aViewIsDragged()) {
            getChildAt(dragged).setScaleX(1.2f);
            getChildAt(dragged).setScaleY(1.2f);
        }
    }

    private TranslateAnimation createTranslateAnimation(Point oldOffset,
            Point newOffset) {
        TranslateAnimation translate = new TranslateAnimation(
                Animation.ABSOLUTE, oldOffset.x, Animation.ABSOLUTE,
                newOffset.x, Animation.ABSOLUTE, oldOffset.y,
                Animation.ABSOLUTE, newOffset.y);
        translate.setDuration(ANIMATION_DURATION);
        translate.setFillEnabled(true);
        translate.setFillAfter(true);
        translate.setInterpolator(new AccelerateDecelerateInterpolator());
        return translate;
    }

    private void animateMoveToNewPosition(View targetView, Point oldOffset,
            Point newOffset) {
//        AnimationSet set = new AnimationSet(true);

//        Animation rotate = createFastRotateAnimation();
        Animation translate = createTranslateAnimation(oldOffset, newOffset);

//        set.addAnimation(rotate);
//        set.addAnimation(translate);
//        set.setFillAfter(true);

        targetView.clearAnimation();
        targetView.startAnimation(translate);

    }

    private boolean aViewIsDragged() {
        return dragged != -1;
    }

    private View createView(int count) {
        HomeEditViewItem view = HomeEditViewItem.newInstance(mContext);
        view.setDefaultChangeListener(this);
        view.setTag(-1);
        return view;
    }

    private void popDeleteView() {

        deleteZone.setVisibility(View.VISIBLE);

        deleteZone.layout(0, 0, deleteZone.getMeasuredWidth(),
                deleteZone.getMeasuredHeight());
    }

    private HomeEditViewItem createAddView() {
        if (add != null) {
            return add;
        }
        add = HomeEditViewItem.getAddView(mContext);
        return add;
    }

    private void hideDeleteView() {
        deleteZone.setVisibility(View.GONE);
    }

    private boolean touchUpInDeleteZoneDrop(int x, int y) {
        Rect zone = new Rect();
        deleteZone.getHitRect(zone);

        if (zone.intersect(x, y, x + 1, y + 1)) {
            deleteZone.smother();
            return true;
        }
        return false;
    }

    private void manageDeleteZoneHover(int x, int y) {
        Rect zone = new Rect();
        deleteZone.getHitRect(zone);

        if (zone.intersect(x, y, x + 1, y + 1)) {
            deleteZone.highlight();
        } else {
            deleteZone.smother();
        }
    }
    public void dismissDialog() {
        if (mDialog != null && mDialog.isShowing()) {
            manageChildrenReordering(false);
            mDialog.dismiss();
        }
    }
}
